package com.example.alipay.anysign;

import cn.org.bjca.anysign.components.bean.message.*;
import cn.org.bjca.anysign.model.p2p.SignExtInfo;
import cn.org.bjca.anysign.terminal.model.AttachmentInfo;
import cn.org.bjca.common.model.DocumentExtType;
import cn.org.bjca.common.model.GeneratePDFInfo;
import cn.org.bjca.common.model.KWRuleInfo;
import cn.org.bjca.seal.esspdf.client.message.ChannelMessage;
import cn.org.bjca.seal.esspdf.client.tools.AnySignClientTool;
import cn.org.bjca.seal.esspdf.client.utils.ClientUtil;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class Angsign {
    // http://223.70.139.221:18002
    AnySignClientTool anySignClientTool = null;

    private String resourcesPath;

    String testEncDataPath;

    String testHtmlFilePath;

    String testPdfFilePath;

    String testXMLFilePath;

    String testImageFilePath;

    String outPdfsFilePath;

    String testSignedPdfFilePath;



    @Before
    public void init() throws Exception {
        String ip = "223.70.139.221";
        int port = 18002;
        anySignClientTool = new AnySignClientTool(ip, port);
        resourcesPath = URLDecoder.decode(this.getClass().getClassLoader().getResource("").getPath(), "UTF-8");

        File directory = new File("../dsvs/src/main/resources");

        testEncDataPath = directory.getCanonicalPath()+"\\anysign\\";
        testHtmlFilePath = directory.getCanonicalPath()+"\\anysign\\";
        testPdfFilePath = directory.getCanonicalPath()+"\\anysign\\";
        testXMLFilePath = directory.getCanonicalPath()+"\\anysign\\";
        testImageFilePath = directory.getCanonicalPath()+"\\anysign\\";
        outPdfsFilePath = directory.getCanonicalPath()+"\\anysign\\";

    }


    /**
     * 加密包签名
     *加密包手写签名 加密包pdf签名
     * @Description:
     * @return:void
     * @throws:
     */
    @Test
    public void testAnySignEncPackage() throws Exception { // 加密包签名
        byte[] encDataBty = ClientUtil.readFileToByteArray(new File(testEncDataPath + "手写签名加密包.txt"));// 加密包字节数组
        long begin = System.currentTimeMillis();
        ChannelMessage message = anySignClientTool.anyWriteEncPackage(encDataBty);
        long end = System.currentTimeMillis();
        System.out.println("********************运行时间:" + (end - begin) / 1000f + "s");
        System.out.println("状态码：" + message.getStatusCode());
        System.out.println("状态信息：" + message.getStatusInfo());
        if ("200".equals(message.getStatusCode())) {// 成功
            System.out.println("成功,PDF保存路径:" + outPdfsFilePath);
            List<MessageBodyReference> messageBodyReferenceList = message.getMessageBodyReferenceList();
            MessageBodyReference messageBodyReference = null;
            for (int i = 0; i < messageBodyReferenceList.size(); i++) {
                messageBodyReference = messageBodyReferenceList.get(i);
                ClientUtil.writeByteArrayToFile(new File(outPdfsFilePath + "pdf签名.pdf"), messageBodyReference.getFileBty());

            }
        }
    }
    /**
     * 验证已签名的pdf
     * @throws Exception
     */
    @Test
    public void pdfVerify() throws Exception {
        byte[] pdfBty = ClientUtil.readFileToByteArray(new File(testEncDataPath + "testAnyWriteChallengeCodeSign_0.pdf"));//pdf 字节数组
        ChannelMessage message = anySignClientTool.pdfVerify(pdfBty);
        System.out.println("状态码：" + message.getStatusCode());
        System.out.println("状态信息："+message.getStatusInfo());
        System.out.println("验证结果：" + new String(message.getBody(),"UTF-8"));
    }



    /**
     * 加密包数据签名
     *
     * @throws Exception
     * @Description:
     */
    @Test
    public void testAnyWriteDataSign() throws Exception {
        String pathname = testEncDataPath + "手写签名加密包.txt";
        byte[] encPackage = FileUtils.readFileToByteArray(new File(pathname));
        ChannelMessage message = anySignClientTool.anyWriteDataSign(encPackage);
        // System.out.println(message.getClientSignList());
        System.out.println("状态码：" + message.getStatusCode());
        System.out.println("状态信息：" + message.getStatusInfo());
        Assert.assertEquals("200", message.getStatusCode());
        if ("200".equals(message.getStatusCode())) {// 成功
            System.out.println("成功,PDF保存路径:" + outPdfsFilePath);
            ClientUtil.writeByteArrayToFile(new File(outPdfsFilePath + "数据签名包.txt"), message.getBody());
        }
    }


    /**
     * <p>数据签名验证</p>
     *
     * @throws Exception
     * @Description:
     */
    @Test
    public void testAnyWriteDataVerify() throws Exception {
        //原文base64值
        String contents = "dGVzdA==";
        String pathname = outPdfsFilePath + "数据签名包.txt";
        byte[] signedPackage = FileUtils.readFileToByteArray(new File(pathname));
        ChannelMessage message = anySignClientTool.anyWriteDataVerify(signedPackage, contents);
        System.out.println("状态码：" + message.getStatusCode());
        System.out.println("状态信息：" + message.getStatusInfo());
        Assert.assertEquals("200", message.getStatusCode());
        if ("200".equals(message.getStatusCode())) {// 成功
            System.out.println("成功,PDF保存路径:" + outPdfsFilePath);
            ClientUtil.writeByteArrayToFile(new File(outPdfsFilePath + "数据签名验证结果.txt"), message.getBody());
        }
    }

    /**
     * 转换base64编码
     */
    @Test
    public void textToBase64(){
        String context="test";
        String base64 = Base64.getEncoder().encodeToString(context.getBytes());
        System.out.println(base64);
    }

    /**
     * 加密包手写签名们面签-一名一签示例
     * @throws IOException
     */
    @Test
   public void anysignFacade() throws Exception {
       byte[] encDataBty = ClientUtil.readFileToByteArray(new File(testEncDataPath + "手写签名加密包.txt"));
       List<ExternalAnyWriteInfo> externalAnyWriteInfoList = new ArrayList<ExternalAnyWriteInfo>(1);
       ExternalAnyWriteInfo externalAnyWriteInfo = new ExternalAnyWriteInfo();
//999999 为测试渠道号，业务集成正式环境时需要改成正式渠道号
       externalAnyWriteInfo.setChannel("999999");
       ExternalEncryptPackageInfo encryptPackageInfo = new ExternalEncryptPackageInfo(encDataBty);
       List<ExternalEncryptPackageInfo> encryptPackageInfoList = new ArrayList<ExternalEncryptPackageInfo>();
       encryptPackageInfoList.add(encryptPackageInfo);
       externalAnyWriteInfo.setEncryptPackageInfoList(encryptPackageInfoList);
       externalAnyWriteInfoList.add(externalAnyWriteInfo);
//调用签名接口
       ChannelMessage message = anySignClientTool.anyWritePDFSignFacade(externalAnyWriteInfoList);
        System.out.println("状态码：" + message.getStatusCode());
        System.out.println("状态信息：" + message.getStatusInfo());
       if ("200".equals(message.getStatusCode())) {
           List<MessageBodyReference> messageBodyReferenceList = message.getMessageBodyReferenceList();
           MessageBodyReference messageBodyReference = null;
           for (int i = 0; i < messageBodyReferenceList.size(); i++) {
               messageBodyReference = messageBodyReferenceList.get(i);
               ClientUtil.writeByteArrayToFile(new File(outPdfsFilePath + "门面手写签名-一名一签.pdf"), messageBodyReference.getFileBty());
           }
       }
   }

    /**
     * 加密包手写签名们面签-多人多签
     * @throws Exception
     */
    @Test
    public void anysignFacade2() throws Exception {
        byte[] encDataBty= ClientUtil.readFileToByteArray(new File(testEncDataPath + "手写签名加密包.txt"));
//        byte[] encDataBty2 = ClientUtil.readFileToByteArray(new File(testEncDataPath + "手写签名加密包.txt"));
// 加密包字节数组   ExternalAnyWriteInfo  加密包手写签名实体类
        List<ExternalAnyWriteInfo> externalAnyWriteInfoList = new ArrayList<ExternalAnyWriteInfo>();
        ExternalAnyWriteInfo externalAnyWriteInfo = null;
        List<ExternalEncryptPackageInfo> encryptPackageInfoList = null;
        for (int i = 0; i < 1; i++) {
            externalAnyWriteInfo = new ExternalAnyWriteInfo();
            //999999 为测试渠道号，业务集成正式环境时需要改成正式渠道号
            externalAnyWriteInfo.setChannel("999999");
            ExternalEncryptPackageInfo encryptPackageInfo = null;
            encryptPackageInfoList = new ArrayList<ExternalEncryptPackageInfo>();
            for (int j = 0; j < 2; j++) {
                //encData、encPath 二者必须设置其中一个。这里选择的是encDate  ExternalEncryptPackageInfo加密包外传封装类
                encryptPackageInfo = new ExternalEncryptPackageInfo(encDataBty);

                Map<Integer, List<AttachmentInfo>> evidenceMap = new HashMap<Integer, List<AttachmentInfo>>();
                List<AttachmentInfo> evidenceList1 = new ArrayList<AttachmentInfo>();
                List<AttachmentInfo> evidenceList2 = new ArrayList<AttachmentInfo>();
                AttachmentInfo evidence1 = new AttachmentInfo();
                evidence1.setFormat(DocumentExtType.IMAGEGIF.name());
                evidence1.setPointHash("2222222222222222222222222222222");//证据生成的 hash 值


                AttachmentInfo evidence2 = new AttachmentInfo();
                evidence2.setFormat(DocumentExtType.IMAGEGIF.name());
                evidence2.setPointHash("11111111111111111111111111111111111111111");

                evidenceList1.add(evidence1);
                evidenceList1.add(evidence2);
                evidenceMap.put(1, evidenceList1);

                evidenceList2.add(evidence1);
                evidenceList2.add(evidence2);

                evidenceMap.put(2, evidenceList2);
                //添加证据
                encryptPackageInfo.setEvidenceList(evidenceMap);
                encryptPackageInfoList.add(encryptPackageInfo);

            }

            //加密包手写签名实体类 ExternalAnyWriteInfo
            externalAnyWriteInfo.setEncryptPackageInfoList(encryptPackageInfoList);
            externalAnyWriteInfoList.add(externalAnyWriteInfo);
            // //结束后10个加密包手写签名实体类    10个里面每一个都有2个附件证据
        }
        ChannelMessage message = anySignClientTool.anyWritePDFSignFacade(externalAnyWriteInfoList);
        System.out.println("状态码：" + message.getStatusCode());
        System.out.println("状态信息：" + message.getStatusInfo());
        if ("200".equals(message.getStatusCode())) {
            List<MessageBodyReference> messageBodyReferenceList = message.getMessageBodyReferenceList();
            MessageBodyReference messageBodyReference = null;
            for (int i = 0; i < messageBodyReferenceList.size(); i++) {
                messageBodyReference = messageBodyReferenceList.get(i);
                ClientUtil.writeByteArrayToFile(new File(outPdfsFilePath + "门面手写签名-多名多签"+i+".pdf"),
                        messageBodyReference.getFileBty());
            }
        }
    }

    /**
     * 生成挑战码 一名一签
     * @throws Exception
     */
    @Test
    public void CreatechangeCodeSign() throws Exception {
        AnyWriteChallengeCodeReqMessage message = new AnyWriteChallengeCodeReqMessage();
        //生成挑战码时，签名人，手机号，身份证号信息为必填项
        message.setSignerName("罗清晨");
        message.setSignerTelephone("13581955021");
        message.setIdCard("371502XXXXXXXX4824");
//1 为身份证，2 为军官证，3 为护照，4 为户口本，5 其他. 默认为 1。no-check 默认为 N,目前只检测 1 和 4。若不检测
        //证件类型，则需要导入 no-check 为的 license。
        message.setIdType("1");
        message.setAlgorithm("SM2"); // RSA、SM2
        message.setPeriod(300); // 设置缓存有效期，单位秒
        SignExtInfo signExtInfo = new SignExtInfo();
        //999999 为测试渠道号，业务集成正式环境时需要改成正式渠道号
        signExtInfo.setBussChannel("999999");
        message.setSignExtInfo(signExtInfo);
// 附件、证据相关信息 证据信息计算 hash 时算法为 sha1
        List<cn.org.bjca.common.model.AttachmentInfo> attachmentInfos = new
                ArrayList<cn.org.bjca.common.model.AttachmentInfo>();
        //设置附件相关信息
        cn.org.bjca.common.model.AttachmentInfo attachmentInfo = new cn.org.bjca.common.model.AttachmentInfo();
//当 setAttach 为 true 时，设置为附件相关的信息
        attachmentInfo.setAttach(true);
        byte[] attachContent = FileUtils.readFileToByteArray(new File(testImageFilePath+"test.png"));
//设置附件内容
        attachmentInfo.setAttachContent(attachContent);
        //设置附件类型
        attachmentInfo.setAttachType(DocumentExtType.IMAGEGIF);
//设置附件 hash 值 算法为 sha1
        attachmentInfo.setEvidenceHash("1234567890");
        attachmentInfos.add(attachmentInfo);
//设置证据相关信息
        cn.org.bjca.common.model.AttachmentInfo evidence = new cn.org.bjca.common.model.AttachmentInfo();
//当 setEvidence 为 true 时，设置为证书相关的信息
        evidence.setEvidence(true);
        byte[] evidenceContent = FileUtils.readFileToByteArray(new File(testImageFilePath+"test.png"));
//设置证据内容
        evidence.setAttachContent(evidenceContent);
//设置证据类型
        evidence.setAttachType(DocumentExtType.IMAGEGIF);
//设置证据 hash 算法为 sha1
        evidence.setEvidenceHash("1234567890");
        evidence.setIndex(1);
        attachmentInfos.add(evidence);
        message.setAttachmentInfos(attachmentInfos);
        message.setIsTss("true"); //是否添加时间戳签名是：true、否：false
// 待签名 PDF
        List<ChallengeCodePDFInfo> pdfInfos = new ArrayList<ChallengeCodePDFInfo>();
        ChallengeCodePDFInfo pdfinfo = new ChallengeCodePDFInfo();
        GeneratePDFInfo generatePDFInfo = new GeneratePDFInfo();
        byte[] docContent = FileUtils.readFileToByteArray(new File(testPdfFilePath+"电子签章管理系统安装部署手册V4.5.0.pdf"));
        generatePDFInfo.setDocContent(docContent);
        generatePDFInfo.setDocumentExtType(DocumentExtType.PDF);
        pdfinfo.setGeneratePDFInfo(generatePDFInfo);
// 设置签名位置信息
        pdfinfo.setSignSuleType("0");
        KWRuleInfo kwRuleInfo = new KWRuleInfo();
        kwRuleInfo.setKW("的");
        kwRuleInfo.setPageno("1");
        kwRuleInfo.setKWOffset("0");
        kwRuleInfo.setKWPos("0");
        kwRuleInfo.setKWXOffset("0");
        kwRuleInfo.setKWYOffset("0");
        pdfinfo.setKwRuleInfo(kwRuleInfo);
        pdfInfos.add(pdfinfo);
        message.setChallengeCodePDFInfos(pdfInfos);
        ChannelMessage channelMessage = anySignClientTool.anyWriteGenerateChallengeCode(message);
        Assert.assertEquals("200", channelMessage.getStatusCode());
        System.out.println("状态码：" + channelMessage.getStatusCode());
        System.out.println("状态信息：" + channelMessage.getStatusInfo());
        if ("200".equals(channelMessage.getStatusCode())){
            System.out.println(new String(channelMessage.getBody()));
        }
    }

    /**
     * 挑战码签名
     */
    @Test
    public void challgeCodeSign() throws Exception {

            AnyWriteChallengeCodeReqMessage message = new AnyWriteChallengeCodeReqMessage();
            message.setTransId("823ff599-b186-441b-88f9-d0671b48befa");
            message.setChallengeCode("195519");
            message.setSignerTelephone("13581955021");
            message.setAlgorithm("SM2");
            ChannelMessage channelMessage = anySignClientTool.anyWriteChallengeCodeSign(message);
            System.out.println("状态码：" + channelMessage.getStatusCode());
              System.out.println("状态信息：" + channelMessage.getStatusInfo());
            if ("200".equals(channelMessage.getStatusCode())) {
                List<MessageBodyReference> messageBodyReferenceList = channelMessage.getMessageBodyReferenceList();
                MessageBodyReference messageBodyReference = null;
                for (int i = 0; i < messageBodyReferenceList.size(); i++) {
                    messageBodyReference = messageBodyReferenceList.get(i);
                    ClientUtil.writeByteArrayToFile(new File(outPdfsFilePath + "挑战码签名" + i + ".pdf"),
                            messageBodyReference.getFileBty());
                    System.out.println("保存路径："+outPdfsFilePath + "挑战码签名" + i + ".pdf");
                }
            }

    }
}
